package fr.insta.reverse.uml.dao;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.NonUniqueObjectException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

import fr.insta.reverse.uml.bean.Projet;
import fr.insta.reverse.uml.bean.User;
import fr.insta.reverse.uml.bean.Visibilite;
import fr.insta.reverse.uml.util.HibernateUtil;

/**
 * DAO for domain model class Projet.
 * @see fr.insta.reverse.uml.bean.Projet
 * @author Valera
 */
@Stateless
public class DaoProjet implements IDao<Projet>
{
	private static final Log log = LogFactory.getLog(DaoProjet.class);

	@Override
	public Projet save(Projet prj)
	{
		log.debug("saving Projet instance");
		try
		{
			Session session = HibernateUtil.currentSession();
			Transaction tx = session.beginTransaction();

			User up = prj.getProp();
			//			up = (User) session.merge(up);
			session.saveOrUpdate(up);

			Visibilite vis = prj.getVisibilite();
			//			vis = (Visibilite) session.merge(vis);
			session.saveOrUpdate(vis);

			prj.setProp(up);
			prj.setVisibilite(vis);

			session.saveOrUpdate(prj);

			tx.commit();
			HibernateUtil.closeSession();
			log.debug("save successful");
			return prj;
		}
		catch (RuntimeException e)
		{
			log.error("save failed", e);
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean remove(Projet prj)
	{
		log.debug("removing Projet instance");
		try
		{
			Session session = HibernateUtil.currentSession();
			Transaction tx = session.beginTransaction();

			Criteria crit = session.createCriteria(Projet.class, "projet");
			crit.createAlias("projet.prop", "usr")
					.add(Restrictions.eq("usr.mail", prj.getProp().getMail()))
					.add(Restrictions.eq("projet.lib", prj.getLib()));
			prj = (Projet) crit.uniqueResult();

			session.delete(prj);

			tx.commit();
			HibernateUtil.closeSession();
			log.debug("remove successful");
			return true;
		}
		catch (RuntimeException e)
		{
			log.error("remove failed", e);
			e.printStackTrace();
		}
		return false;
	}

	@Override
	public Projet findById(int id)
	{
		log.debug("getting Projet instance with id: " + id);
		try
		{
			Session session = HibernateUtil.currentSession();

			Projet instance = (Projet) session.createCriteria(Projet.class)
					.add(Restrictions.eq("id", id))
					.uniqueResult();

			HibernateUtil.closeSession();
			log.debug("get successful");
			return instance;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	//	public List<Projet> getByLib(String lib)
	//	{
	//		log.debug("getting all Projets by lib : " + lib);
	//		List<Projet> listprojets = new ArrayList<Projet>();
	//		try
	//		{
	//			Session session = HibernateUtil.currentSession();
	//
	//			listprojets = (List<Projet>) session.createCriteria(Projet.class)
	//					.add(Restrictions.like("lib", lib, MatchMode.ANYWHERE))
	//					.add(Restrictions.eq("lib", lib))
	//					.list();
	//
	//			HibernateUtil.closeSession();
	//			log.debug("get successful");
	//			return listprojets;
	//		}
	//		catch (RuntimeException re)
	//		{
	//			log.error("get failed", re);
	//			re.printStackTrace();
	//		}
	//		return null;
	//	}

	public List<Projet> getByLib(Projet prj)
	{
		log.debug("getting projets by lib : " + prj.getLib());
		List<Projet> listP = new ArrayList<Projet>();
		List<Projet> listPpub = new ArrayList<Projet>();
		try
		{
			Session session = HibernateUtil.currentSession();
			Criteria crit;

			// getting user's projects where lib like prj.getLib()
			if (prj.getProp() != null)
			{
				crit = session.createCriteria(Projet.class, "projet");
				crit.createAlias("projet.prop", "usr")
						.createAlias("projet.visibilite", "vis")
						.add(Restrictions.eq("usr.mail", prj.getProp().getMail()))
						.add(Restrictions.like("projet.lib", prj.getLib(), MatchMode.ANYWHERE))
						.addOrder(Order.asc("vis.id"));
				listP = (List<Projet>) crit.list();
			}

			// getting public projects where lib like prj.getLib()
			crit = session.createCriteria(Projet.class, "projet");
			crit.createAlias("projet.visibilite", "vis")
					.add(Restrictions.eq("vis.lib", "Publique"))
					.add(Restrictions.like("projet.lib", prj.getLib(), MatchMode.ANYWHERE))
					.addOrder(Order.asc("vis.id"));

			if (prj.getProp() != null)
			{
				crit.createAlias("projet.prop", "usr")
						.add(Restrictions.ne("usr.mail", prj.getProp().getMail()));
			}
			listPpub = (List<Projet>) crit.list();

			listP.addAll(listPpub);

			HibernateUtil.closeSession();
			log.debug("get successful");
			return listP;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	public Projet getByLibAndUser(Projet prj)
	{
		log.debug("getting all Projets by lib : " + prj.getLib() + " and by User : " + prj.getProp().getPrenom() + " " + prj.getProp().getNom());
		try
		{
			Session session = HibernateUtil.currentSession();

			Criteria crit = session.createCriteria(Projet.class, "projet");
			crit.createAlias("projet.prop", "usr")
					.add(Restrictions.eq("usr.mail", prj.getProp().getMail()))
					.add(Restrictions.eq("projet.lib", prj.getLib()));
			prj = (Projet) crit.uniqueResult();

			HibernateUtil.closeSession();
			log.debug("get successful");
			return prj;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	@Override
	public List<Projet> getAll()
	{
		log.debug("getting all Projets");
		List<Projet> listprojets = new ArrayList<Projet>();
		try
		{
			Session session = HibernateUtil.currentSession();

			listprojets = (List<Projet>) session.createCriteria(Projet.class).list();

			HibernateUtil.closeSession();
			log.debug("get successful");
			return listprojets;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	public List<Projet> getUserProjects(User usr)
	{
		log.debug("getting user Projets");
		List<Projet> listprojets = new ArrayList<Projet>();
		try
		{
			Session session = HibernateUtil.currentSession();

			Criteria crit = session.createCriteria(Projet.class, "projet");
			crit.createAlias("projet.prop", "usr")
					.add(Restrictions.eq("usr.mail", usr.getMail()));
			listprojets = (List<Projet>) crit.list();

			HibernateUtil.closeSession();
			log.debug("get successful");
			return listprojets;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	public List<Projet> getPublicProjects()
	{
		log.debug("getting public Projets");
		List<Projet> listprojets = new ArrayList<Projet>();
		try
		{
			Session session = HibernateUtil.currentSession();

			Criteria crit = session.createCriteria(Projet.class, "projet");
			crit.createAlias("projet.visibilite", "visibilite");
			crit.add(Restrictions.eq("visibilite.lib", "Publique"))
					.addOrder(Order.asc("visibilite.id"));
			listprojets = (List<Projet>) crit.list();

			HibernateUtil.closeSession();
			log.debug("get successful");
			return listprojets;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	public Projet findByImageHash(String imageHash)
	{
		try
		{
			Session session = HibernateUtil.currentSession();

			Projet instance = (Projet) session.createCriteria(Projet.class)
					.add(Restrictions.eq("imgHash", imageHash))
					.uniqueResult();

			HibernateUtil.closeSession();
			log.debug("get successful");
			return instance;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	public List<Projet> getUserAndPublicProjects(User usr)
	{
		log.debug("getting usr and public Projets");
		List<Projet> listP = new ArrayList<Projet>();
		List<Projet> listPpub = new ArrayList<Projet>();
		try
		{
			Session session = HibernateUtil.currentSession();
			Criteria crit;

			// getting user's projects
			if (usr != null)
			{
				crit = session.createCriteria(Projet.class, "projet");
				crit.createAlias("projet.prop", "usr")
						.createAlias("projet.visibilite", "vis")
						.add(Restrictions.eq("usr.mail", usr.getMail()))
						.addOrder(Order.asc("vis.id"));
				listP = (List<Projet>) crit.list();
			}

			// getting public projects
			crit = session.createCriteria(Projet.class, "projet");
			crit.createAlias("projet.visibilite", "vis")
					.add(Restrictions.eq("vis.lib", "Publique"))
					.addOrder(Order.asc("vis.id"));

			if (usr != null)
			{
				crit.createAlias("projet.prop", "usr")
						.add(Restrictions.ne("usr.mail", usr.getMail()));
			}
			listPpub = (List<Projet>) crit.list();

			listP.addAll(listPpub);

			HibernateUtil.closeSession();
			log.debug("get successful");
			return listP;
		}
		catch (RuntimeException re)
		{
			log.error("get failed", re);
			re.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean deleteAll()
	{
		log.debug("deleting all Projets");
		try
		{
			Session session = HibernateUtil.currentSession();
			Transaction tx = session.beginTransaction();

			session.createQuery("delete from Projet").executeUpdate();

			tx.commit();
			HibernateUtil.closeSession();
			log.debug("delete successful");
			return true;
		}
		catch (RuntimeException re)
		{
			log.error("delete failed", re);
			re.printStackTrace();
		}
		return false;
	}
}
